package io.renren.modules.app.service.impl;

import cn.hutool.db.sql.Order;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
import com.github.wxpay.sdk.WXPayUtil;
import io.renren.common.aliPay.AliConfig;
import io.renren.common.aliPay.AliPayHelper;
import io.renren.common.enums.ErrorCode;
import io.renren.common.exception.RRException;
import io.renren.common.utils.*;
import io.renren.common.wxPay.WxConfig;
import io.renren.common.wxPay.WxPayHelper;
import io.renren.common.wxPay.WxPayReqDto;
import io.renren.modules.app.dto.CreateOrderRespDto;
import io.renren.modules.app.entity.BalanceLogEntity;
import io.renren.modules.app.entity.CustomerEntity;
import io.renren.modules.app.entity.GoodsEntity;
import io.renren.modules.app.req.CreateOrderInfoReq;
import io.renren.modules.app.req.CreateOrderReq;
import io.renren.modules.app.service.BalanceLogService;
import io.renren.modules.app.service.CustomerService;
import io.renren.modules.app.service.GoodsService;
import io.renren.modules.app.utils.AuthUtils;
import io.renren.modules.app.vo.CreateOrderPayVO;
import io.renren.modules.app.vo.CreateOrderVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import io.renren.modules.app.dao.OrderDao;
import io.renren.modules.app.entity.OrderEntity;
import io.renren.modules.app.service.OrderService;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;


@Service("orderService")
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    @Resource
    private GoodsService goodsService;

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private WxConfig wxConfig;

    @Resource
    protected WxPayHelper wxPayHelper;

    @Resource
    private AliConfig aliConfig;

    @Resource
    protected AliPayHelper aliPayHelper;

    @Resource
    private HttpServletRequest httpServletRequest;

    @Resource
    private CustomerService customerService;

    @Resource
    private BalanceLogService balanceLogService;



    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * @description: 用户创建订单
     * @auther: create by Administrator - MR.XU email:260139486@qq.com
     * @date 2021-01-19 10:04:49
     * @param createOrderReq
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public CreateOrderVO createOrder(CreateOrderReq createOrderReq) {
        //初步校验
        if(CheckParam.isNull(createOrderReq.getGoodsList())){
            throw new RRException(ErrorCode.PARAM_ERROR.getMessage(),ErrorCode.PARAM_ERROR.getCode());
        }
        //创建订单
        OrderEntity userOrder = new OrderEntity();
        //1.封装基础参数
        userOrder.setUserId(AuthUtils.getUserId());
        userOrder.setFreight(createOrderReq.getFreight());//运费
        if (!CheckParam.isNull(createOrderReq.getOrderRemark())){
            userOrder.setRemark(createOrderReq.getOrderRemark());
        }
        userOrder.setAddress(createOrderReq.getAddress());//配送地址
        userOrder.setMobile(createOrderReq.getMobile());//联系方式
        userOrder.setReceiver(createOrderReq.getReceiver());//收货人
        BigDecimal totalMoney = BigDecimal.valueOf(0);
        int totalNum = 0;
        StringBuilder detail = new StringBuilder();
        //4.封装订单商品图片
        for (CreateOrderInfoReq createOrderInfoReq :createOrderReq.getGoodsList() ){
            //查询商品
            GoodsEntity goods = goodsService.getById(createOrderInfoReq.getGoodsId());
            if(CheckParam.isNull(goods)){
                throw new RRException(ErrorCode.PARAM_ERROR.getMessage(),ErrorCode.PARAM_ERROR.getCode());
            }
            //修改库存
            goods.setSalesNum(goods.getSalesNum()+createOrderInfoReq.getBuySum());
            //查询对应商品主图
            String img = goods.getThumbnail();
            //添加
            totalNum = totalNum + createOrderInfoReq.getBuySum();
            BigDecimal money =  goods.getPrice().multiply(BigDecimal.valueOf(createOrderInfoReq.getBuySum()));
            totalMoney = totalMoney.add(money);
            detail.append(goods.getName()+"*"+createOrderInfoReq.getBuySum()+";");
        }
        userOrder.setTotalPrice(totalMoney);//订单金额
        userOrder.setTotalNum(totalNum);//订单金额
        userOrder.setDetails(detail.toString());
//        createOrderReq.getGoodsList().stream().forEach(createOrderInfoReq -> {
//            //查询商品
//            GoodsEntity goods = goodsService.getById(createOrderInfoReq.getGoodsId());
//            if(CheckParam.isNull(goods)){
//                throw new RRException(ErrorCode.PARAM_ERROR.getMessage(),ErrorCode.PARAM_ERROR.getCode());
//            }
//            //修改库存
//            goods.setSalesNum(goods.getSalesNum()+createOrderInfoReq.getBuySum());
//            //查询对应商品主图
//            String img = goods.getThumbnail();
//            //添加
//            totalNum = totalNum + createOrderInfoReq.getBuySum();
//            totalMoney = totalMoney.add(goods.getPrice());
//        });
        userOrder.setStatus(1);
        this.save(userOrder);
        //6.存入redis缓存
//        String redisKey = RedisConstants.ORDER_USER_CREATE_UNPAY+userOrder.getUserOrderId();
//        redisRepository.set(redisKey,userOrder.getUserOrderId(),15L, TimeUnit.MINUTES);

        //7.创建返回
        CreateOrderVO resp = new CreateOrderVO();
        resp.setOrderNo(userOrder.getOrderNumber());
        resp.setOrderId(userOrder.getId());
        return resp;
    }
    /**
     * @description: 取消订单
     * @auther: create by Administrator - MR.XU email:260139486@qq.com
     * @date 2021-01-19 10:04:49
     * @param orderId
     * @return
     */
    @Override
    public void cancelOrder(String orderId) {
        OrderEntity order = this.getOne(new QueryWrapper<OrderEntity>().eq("id",orderId).eq("user_id",AuthUtils.getUserId()));
        if(CheckParam.isNull(order)){
            throw new RRException(ErrorCode.NOT_EXSIZE_ORDER.getMessage(),ErrorCode.NOT_EXSIZE_ORDER.getCode());
        }
        order.setStatus(0);
        Boolean ret = this.update(order,new QueryWrapper<OrderEntity>().eq("id",orderId).eq("status",1));
        if(!ret){
            throw new RRException("操作失败",ErrorCode.ERROR.getCode());
        }
    }
    /**
     * @description: 继续支付
     * @auther: create by Administrator - MR.XU email:260139486@qq.com
     * @date 2021-01-19 10:04:49
     * @param orderCode
     * @return
     */
    @Override
    public CreateOrderPayVO continuePay(String orderCode) {
        CreateOrderPayVO respDto = new CreateOrderPayVO();
        final OrderEntity order = this.getOne(new QueryWrapper<OrderEntity>().eq("order_number",orderCode.trim()).eq("status",1).eq("user_id",AuthUtils.getUserId()));
        if (CheckParam.isNull(order)) {
            throw new RRException(ErrorCode.ERROR_ORDER_ID_PARAM.getMessage(),ErrorCode.ERROR_ORDER_ID_PARAM.getCode());
        }
        respDto.setNeedPay(true);
        respDto.setOrderCode(orderCode);
        respDto.setPayType(order.getPayType());
        final String pay = redisUtils.get(orderCode);
        //只有微信支付和支付宝支付情况
        if (StringUtils.isNotBlank(pay)) {
            switch (order.getPayType()) {
                case 1:
                    try {
                        String sign = "";
                        JSONObject jsonObject = JSON.parseObject(pay);
                        jsonObject.put("timeStamp", String.valueOf(Timestamp.valueOf(LocalDateTime.now()).getTime() / 1000));
                        sign = WXPayUtil.generateSignature((Map) jsonObject, wxConfig.getKey());
                        jsonObject.put("paySign", sign);
                        respDto.setPayHub(jsonObject);
                    } catch (Exception e) {
                        throw new RRException("请求微信支付失败",2001 );
                    }
                    break;
                case 2:
                    respDto.setPayHub(JSON.parseObject(pay));
                    break;
                default:
                    throw new RRException(ErrorCode.ERROR.getMessage(),ErrorCode.ERROR.getCode());
            }
        } else {
            //重新发起支付
            order.setOrderNumber(SnowflakeIdWorker.getNextOrderNo("SPDD"));
            this.pay(order, respDto);
            this.updateById(order);
        }
        return respDto;
    }

    /**
     * @description: 余额支付
     * @auther: create by Administrator - MR.XU email:260139486@qq.com
     * @date 2021-01-19 10:04:49
     * @param orderCode
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void orderBalancePay(String orderCode) {
        final OrderEntity order = this.getOne(new QueryWrapper<OrderEntity>().eq("order_number",orderCode.trim()).eq("status",1).eq("user_id",AuthUtils.getUserId()));
        if (CheckParam.isNull(order)) {
            throw new RRException(ErrorCode.ERROR_ORDER_ID_PARAM.getMessage(),ErrorCode.ERROR_ORDER_ID_PARAM.getCode());
        }
        CustomerEntity customer = customerService.getById(AuthUtils.getUserId());
        //如果订单金额大于余额
        if(order.getTotalPrice().compareTo(customer.getBalance()) ==1){
            throw new RRException(ErrorCode.ERROR_LOW_BALANCE.getMessage(),ErrorCode.ERROR_LOW_BALANCE.getCode());
        }
        Boolean ret = customerService.update(null,new UpdateWrapper<CustomerEntity>().eq("user_id",AuthUtils.getUserId()).eq("balance",customer.getBalance()).setSql(" balance = balance - " +order.getTotalPrice()));
        if(ret){
            Boolean orderRet =  this.update(null,new UpdateWrapper<OrderEntity>().eq("id",order.getId()).eq("status",1).set("status",2).set("pay_type",3).set("pay_time",LocalDateTime.now()));
            if(!orderRet){
                throw new RRException(ErrorCode.NOT_PAY_ERROR.getMessage(),ErrorCode.NOT_PAY_ERROR.getCode());
            }
            CustomerEntity customers = customerService.getById(AuthUtils.getUserId());
            BalanceLogEntity balanceLog = new BalanceLogEntity();
            balanceLog.setUserId(AuthUtils.getUserId());
            balanceLog.setCreateTime((int) LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")));
            balanceLog.setSource(6);
            balanceLog.setType(1);
            balanceLog.setRemark("购买商品");
            balanceLog.setNum(order.getTotalPrice());
            balanceLog.setNowNum(customers.getBalance());
            balanceLog.setDetailRemark("购买商品");
            balanceLog.setOrderNumber(order.getOrderNumber());
            balanceLogService.save(balanceLog);
            //耗时操作
//            this.dataDeal();
        }else {
            throw new RRException(ErrorCode.NOT_PAY_ERROR.getMessage(),ErrorCode.NOT_PAY_ERROR.getCode());
        }
    }

    @Async
    public void dataDeal() {
        for (int i=0; i<100000;i++){
            System.out.println("耗时操作");
        }
    }

    /**
     * @description: 第三天支付处理
     * @auther: create by Administrator - MR.XU email:260139486@qq.com
     * @date 2021-01-19 10:04:49
     * @param order
     * @return
     */
    private void pay(OrderEntity order, CreateOrderPayVO respDto) {
        // todo 请求第三方支付 需要支付的 支付请求返回参数 缓存十分钟 或者在订单完成时 删除缓存
        switch (respDto.getPayType()) {
            case 1:
                WxPayReqDto reqDto = new WxPayReqDto();
                reqDto.setBody(String.format("%s订单:%s", "购买商品", order.getOrderNumber()));
                reqDto.setSpbill_create_ip(IPUtils.getIpAddr(httpServletRequest));
                reqDto.setOut_trade_no(order.getOrderNumber());
                reqDto.setTotal_fee(String.valueOf(order.getTotalPrice().multiply(BigDecimal.valueOf(100)).intValue()));
                final Map<String, String> pay = wxPayHelper.pay(reqDto);
                JSONObject payMap = new JSONObject();
                String sign = "";
                try {
//                    payMap.put("package", String.format("prepay_id=%s", pay.get("prepay_id")));
                    //封装微信app支付参数
                    payMap.put("package", "Sign=WXPay");
                    payMap.put("partnerid", wxConfig.getMchID());
                    payMap.put("prepayid", pay.get("prepay_id"));
                    payMap.put("noncestr", pay.get("nonce_str"));
                    payMap.put("appid", pay.get("appid"));
//                    payMap.put("signtype", "MD5");
                    redisUtils.set(order.getOrderNumber(), payMap.toJSONString(), 1800L);
                    payMap.put("timestamp", String.valueOf(Timestamp.valueOf(LocalDateTime.now()).getTime() / 1000));
                    sign = WXPayUtil.generateSignature((Map) payMap, wxConfig.getKey());
                } catch (Exception e) {
                    throw new RRException("请求微信支付失败",2001);
                }
                payMap.put("sign", sign);
                respDto.setPayHub(payMap);
                break;
            case 2:
                try {
                    JSONObject payHub = new JSONObject();
                    AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
                    model.setBody(String.format("订单%s-%s", "购买商品", order.getOrderNumber()));
                    model.setSubject(String.format("%s订单:%s", "购买商品", order.getOrderNumber()));
                    model.setOutTradeNo(order.getOrderNumber());
                    model.setTimeoutExpress("30m");
                    model.setTotalAmount(String.valueOf(order.getTotalPrice().doubleValue()));
                    final String pay1 = aliPayHelper.pay(model);
                    payHub.put("appid", aliConfig.getAppId());
                    payHub.put("alipay", pay1);
                    redisUtils.set(order.getOrderNumber(), payHub.toJSONString(), 1800L);
                    respDto.setPayHub(payHub);
                } catch (Exception e) {
                    throw new RRException("请求支付宝支付失败",2001);
                }
                break;
            default:
                break;
        }
    }
}